import netscape.javascript.*;
//import processing.core.*;
import traer.physics.*;
//import org.json.JSONObject;
//import org.json.JSONArray;

/*
 * ParticleSystem variables
 */
ParticleSystem physics;
Particle grabbed;
Particle me;

int screenWidth = 600;
int screenHeight = 500;

float mass = 1.0f;
float g = 0.0f;
float drag = 0.5f;

float springStrength = 0.5f;
float springDamp = 0.5f;

float attracStrength = -300;
float attracMinDist = 0;

int framerate = 30;
int bgColor = 99;
int objDiameter = 20;

int maxDiameter = 20;
int minDiameter = 5;

float maxDistance = 250;
float minDistance = 40;

int maxScore = 0;
int minScore = 2147483647;

PFont font;

/*
 * Default Weight
 */
int messageWeight = 1;
int postWeight = 1;
int commentWeight = 1;
int likeWeight = 1;

/*
 * Checked
 */
boolean messageChecked = true;
boolean postChecked = true;
boolean commentChecked = true;
boolean likeChecked = true;

/*
 * Threshold
 */
int threshold = 0;

//Hashtables for friends network
Hashtable<Particle, Friend> friendsTable = new Hashtable<Particle, Friend>();
Hashtable<String, Particle> particleTable = new Hashtable<String, Particle>();

/*
 * Drag
 */

float absPointX = 0;
float absPointY = 0;
float prevMouseX = 0;
float prevMouseY = 0;
float moveX = 0;
float moveY = 0;

boolean isDragged = false;

/*
 * CODE FOR TEST
 */
// Numeber of TEST Particles
//int numberOfParticles = 10;

////Friend data
//String friend_data = "{\"type\": \"friend\",\"data\": [{\"fId\" : \"15720738\",\"name\" : \"Kyounghee Kwon\"},{\"fId\" : \"509400009\",\"name\" : \"Alexandra Wingate\"},{\"fId\" : \"509836156\",\"name\" : \"Laurence Cliff\"},{\"fId\" : \"520468704\",\"name\" : \"Heejin Kim\"},{\"fId\" : \"534124579\",\"name\" : \"Chungshik Moon\"},{\"fId\" : \"542016885\",\"name\" : \"Jongwoo Nam\"},{\"fId\" : \"550118413\",\"name\" : \"Stef Gre\"},{\"fId\" : \"555926326\",\"name\" : \"Adam Coulson\"},{\"fId\" : \"572356495\",\"name\" : \"Jaeeun Chung\"},{\"fId\" : \"573168545\",\"name\" : \"Hoseok Cho\"},{\"fId\" : \"607711964\",\"name\" : \"Kun Woo Kim\"},{\"fId\" : \"612139051\",\"name\" : \"Kerry Marie Millerick\"},{\"fId\" : \"612484233\",\"name\" : \"Moon Myung Hyo\"},{\"fId\" : \"639171815\",\"name\" : \"Su Jin Hong\"},{\"fId\" : \"645061280\",\"name\" : \"TaeYoung Ahn\"},{\"fId\" : \"703412893\",\"name\" : \"Yoonmi Eom\"},{\"fId\" : \"711806955\",\"name\" : \"Arkadiusz Lendzian\"},{\"fId\" : \"720480184\",\"name\" : \"Hitesh Mohabeer\"},{\"fId\" : \"732486215\",\"name\" : \"Anne Lee\"},{\"fId\" : \"765455726\",\"name\" : \"Minji Kim\"},{\"fId\" : \"855739608\",\"name\" : \"WY Paik\"},{\"fId\" : \"1128757552\",\"name\" : \"Oh Sei Hoon Dan\"},{\"fId\" : \"1185268272\",\"name\" : \"Jung Han Woo\"},{\"fId\" : \"1281934594\",\"name\" : \"Seung-woo Lee\"},{\"fId\" : \"1356805212\",\"name\" : \"Philippe Coulon\"},{\"fId\" : \"1379851573\",\"name\" : \"Yohan Lee\"},{\"fId\" : \"1382591304\",\"name\" : \"Gopi Krishna C P\"},{\"fId\" : \"1436029649\",\"name\" : \"Bindu Keerthy\"},{\"fId\" : \"1452136143\",\"name\" : \"Sarah Bak\"},{\"fId\" : \"1468604886\",\"name\" : \"Lim Sungchol\"},{\"fId\" : \"1481610536\",\"name\" : \"Jinhan Kim\"},{\"fId\" : \"1535926803\",\"name\" : \"Lee MacBain\"},{\"fId\" : \"1535994324\",\"name\" : \"Youn Jin Choi\"},{\"fId\" : \"1547370475\",\"name\" : \"Thai-ngoc Duong\"},{\"fId\" : \"1559108118\",\"name\" : \"Anastasios Thanopoulos\"},{\"fId\" : \"1637340897\",\"name\" : \"Mj Park\"},{\"fId\" : \"1676325929\",\"name\" : \"Iktae Sohn\"},{\"fId\" : \"1847145997\",\"name\" : \"Sang Joon Hong\"},{\"fId\" : \"100000036440363\",\"name\" : \"Dawoon Han\"},{\"fId\" : \"100000243514929\",\"name\" : \"???\"},{\"fId\" : \"100000293254433\",\"name\" : \"Kevin Hong\"},{\"fId\" : \"100000416787478\",\"name\" : \"Yool Park\"},{\"fId\" : \"100000525262538\",\"name\" : \"Jaesun Park\"},{\"fId\" : \"100000526102422\",\"name\" : \"SangMi Aureliae Choe\"},{\"fId\" : \"100000545529457\",\"name\" : \"Jeongyeol Kwak\"},{\"fId\" : \"100000550522019\",\"name\" : \"Onesixx Chung\"},{\"fId\" : \"100000560912448\",\"name\" : \"Sanghee Park\"},{\"fId\" : \"100000568852321\",\"name\" : \"Bum-Jo Kim\"},{\"fId\" : \"100000571402532\",\"name\" : \"???\"},{\"fId\" : \"100000591117659\",\"name\" : \"???\"},{\"fId\" : \"100000633970805\",\"name\" : \"Jeongkyu Shin\"},{\"fId\" : \"100000767659366\",\"name\" : \"Jooyeon Kim\"},{\"fId\" : \"100000942474356\",\"name\" : \"Yun-sok Kim\"},{\"fId\" : \"100001041562777\",\"name\" : \"Youngwook Kang\"},{\"fId\" : \"100001057185849\",\"name\" : \"Hee Seung Lee\"},{\"fId\" : \"100001183707930\",\"name\" : \"GeonHyeong Lee\"},{\"fId\" : \"100001190968071\",\"name\" : \"???\"},{\"fId\" : \"100001197734599\",\"name\" : \"Hwa Joo Ryoo\"},{\"fId\" : \"100001278657897\",\"name\" : \"Seongkeun Choi\"},{\"fId\" : \"100001297801606\",\"name\" : \"Hyunmin Cho\"},{\"fId\" : \"100001324002549\",\"name\" : \"Hyanghee Lee\"},{\"fId\" : \"100001373067166\",\"name\" : \"???\"},{\"fId\" : \"100001411220037\",\"name\" : \"Jong Seok Lee\"},{\"fId\" : \"100001437546761\",\"name\" : \"???\"},{\"fId\" : \"100001442696712\",\"name\" : \"Ho Im Lee\"},{\"fId\" : \"100001474516590\",\"name\" : \"Kwang Hyun Park\"},{\"fId\" : \"100001496104711\",\"name\" : \"Jaeho Chung\"},{\"fId\" : \"100001562863238\",\"name\" : \"Kyungjong Jung\"},{\"fId\" : \"100001573101794\",\"name\" : \"Jeongkwon Park\"},{\"fId\" : \"100001616612326\",\"name\" : \"Jinsang Hwang\"},{\"fId\" : \"100001623437056\",\"name\" : \"Hyunju Kim\"},{\"fId\" : \"100001660120678\",\"name\" : \"Sang Chul Kim\"},{\"fId\" : \"100001736213735\",\"name\" : \"Seungbum Jo\"},{\"fId\" : \"100001753717079\",\"name\" : \"Donghyun Lee\"},{\"fId\" : \"100001770838666\",\"name\" : \"???\"},{\"fId\" : \"100001794018281\",\"name\" : \"Hee Kyong Kim\"},{\"fId\" : \"100001838323910\",\"name\" : \"DongChul Igoon\"},{\"fId\" : \"100001871979183\",\"name\" : \"Min Gyu Lee\"},{\"fId\" : \"100001875630715\",\"name\" : \"Minyoung Jeong\"},{\"fId\" : \"100001899332883\",\"name\" : \"Soojin Sohn\"},{\"fId\" : \"100001963907431\",\"name\" : \"Donghyun Kim\"}]}";
//String sample_data = "{\"mode\":1048575,\"data\":{\"100000416787478\":{\"2\" : \"2\",\"256\" : \"14\",\"512\" : \"1\",\"1024\" : \"3\",\"2048\" : \"1\",\"65536\" : \"10\",\"262144\" : \"4\"},\"612139051\":{\"1\" : \"17\",\"2\" : \"2\",\"8\" : \"4\",\"32\" : \"1\",\"256\" : \"2\",\"512\" : \"2\",\"131072\" : \"1\"},\"100000525262538\":{\"1\" : \"1\",\"2\" : \"2\",\"256\" : \"12\",\"512\" : \"1\",\"1024\" : \"6\",\"2048\" : \"2\",\"65536\" : \"2\"},\"509836156\":{\"1\" : \"18\",\"2\" : \"3\",\"256\" : \"1\"},\"100000526102422\":{\"8\" : \"4\",\"256\" : \"10\",\"1024\" : \"6\"},\"1559108118\":{\"1\" : \"19\"},\"100001871979183\":{\"8\" : \"1\",\"256\" : \"10\",\"512\" : \"3\",\"1024\" : \"1\",\"2048\" : \"2\",\"131072\" : \"1\"},\"100001197734599\":{\"256\" : \"16\",\"2048\" : \"1\"},\"100001623437056\":{\"8\" : \"1\",\"32\" : \"1\",\"256\" : \"5\",\"1024\" : \"1\",\"2048\" : \"1\",\"8192\" : \"1\",\"65536\" : \"2\",\"131072\" : \"1\",\"262144\" : \"3\"},\"100000560912448\":{\"8\" : \"1\",\"256\" : \"1\",\"512\" : \"1\",\"2048\" : \"6\",\"65536\" : \"3\",\"131072\" : \"1\",\"262144\" : \"2\"},\"1468604886\":{\"1\" : \"1\",\"2\" : \"8\",\"8\" : \"1\",\"256\" : \"2\"},\"1382591304\":{\"8\" : \"1\",\"256\" : \"8\",\"512\" : \"1\",\"65536\" : \"1\"},\"100001736213735\":{\"2\" : \"1\",\"8\" : \"1\",\"256\" : \"5\",\"512\" : \"1\",\"1024\" : \"2\",\"65536\" : \"1\"},\"100000767659366\":{\"1\" : \"3\",\"2\" : \"4\",\"8\" : \"2\",\"1024\" : \"1\"},\"100001442696712\":{\"8\" : \"1\",\"32\" : \"1\",\"64\" : \"1\",\"256\" : \"4\",\"1024\" : \"1\",\"8192\" : \"1\"},\"711806955\":{\"1\" : \"5\",\"2\" : \"2\",\"8\" : \"1\",\"131072\" : \"1\"},\"1452136143\":{\"1\" : \"2\",\"2\" : \"1\",\"8\" : \"2\",\"32\" : \"1\",\"256\" : \"2\"},\"100001496104711\":{\"2\" : \"2\",\"256\" : \"3\",\"65536\" : \"1\",\"131072\" : \"1\",\"262144\" : \"1\"},\"703412893\":{\"64\" : \"1\",\"128\" : \"2\",\"256\" : \"3\"},\"100001278657897\":{\"8\" : \"1\",\"256\" : \"4\",\"2048\" : \"1\"},\"534124579\":{\"8\" : \"1\",\"128\" : \"1\",\"256\" : \"1\",\"2048\" : \"2\"},\"100001057185849\":{\"256\" : \"2\",\"65536\" : \"3\"},\"720480184\":{\"1\" : \"2\",\"8\" : \"1\",\"8192\" : \"1\",\"65536\" : \"1\"},\"645061280\":{\"1\" : \"1\",\"2\" : \"1\",\"256\" : \"2\",\"1024\" : \"1\"},\"732486215\":{\"1\" : \"1\",\"256\" : \"4\"},\"100001660120678\":{\"256\" : \"5\"},\"100001324002549\":{\"256\" : \"3\",\"65536\" : \"1\"},\"573168545\":{\"128\" : \"2\",\"2048\" : \"2\"},\"572356495\":{\"2\" : \"2\",\"1024\" : \"1\"},\"1676325929\":{\"1\" : \"1\",\"256\" : \"2\"},\"100001963907431\":{\"256\" : \"2\",\"2048\" : \"1\"},\"555926326\":{\"1\" : \"2\",\"8\" : \"1\"},\"100001770838666\":{\"1024\" : \"1\",\"262144\" : \"1\"},\"1535994324\":{\"8\" : \"1\",\"128\" : \"1\"},\"607711964\":{\"256\" : \"2\"},\"100001875630715\":{\"256\" : \"1\",\"2048\" : \"1\"},\"1128757552\":{\"512\" : \"1\",\"131072\" : \"1\"},\"1637340897\":{\"1\" : \"1\",\"8\" : \"1\"},\"1356805212\":{\"1\" : \"1\",\"8\" : \"1\"},\"1847145997\":{\"1\" : \"1\",\"2048\" : \"1\"},\"100001297801606\":{\"1\" : \"1\",\"8\" : \"1\"},\"15720738\":{\"8\" : \"2\"},\"550118413\":{\"1\" : \"1\",\"2\" : \"1\"},\"100000591117659\":{\"256\" : \"1\"},\"591658379\":{\"1\" : \"1\"},\"100000293254433\":{\"2\" : \"1\"},\"100000243514929\":{\"8192\" : \"1\"},\"100000942474356\":{\"32\" : \"1\"},\"643085324\":{\"1\" : \"1\"},\"100000568852321\":{\"2\" : \"1\"},\"100001753717079\":{\"1\" : \"1\"},\"100001183707930\":{\"8\" : \"1\"},\"100001838323910\":{\"8\" : \"1\"},\"1034778664\":{\"1\" : \"1\"},\"100000545529457\":{\"1\" : \"1\"},\"1436029649\":{\"8\" : \"1\"},\"520468704\":{\"1\" : \"1\"},\"100001373067166\":{\"256\" : \"1\"}}}";


/*
 *  Member Methods
 */
void setup() {
  physics = new ParticleSystem(g, drag);
  physics.setIntegrator(ParticleSystem.MODIFIED_EULER);

  this.size(screenWidth,screenHeight);
  this.smooth();
  this.strokeWeight(0);
  this.ellipseMode(CENTER);
  this.frameRate(framerate); //Default 60
  font = createFont("Verdana-Bold", 11);
  this.textFont(font);
  this.colorMode(HSB, 360, 100, 100);  

  initProgram();
  
}

void initProgram() {
  me = physics.makeParticle(mass, width/2, height/2, 0);
  if(me != null) {
    friendsTable.put(me, new Friend("me", "me"));

    particleTable.put("me", me);
    me.makeFixed();
  }
}

void createParticlesTest(int maxNumberOfParticles) {
  if(physics.numberOfParticles() < maxNumberOfParticles) {
    addFriend("id"+physics.numberOfParticles(), "Friend 123", int(random(0,100)), int(random(0,100)), int(random(0,100)), int(random(0,100)));
  }
}

void draw() {

  try {
    //    createParticlesTest(numberOfParticles);

    physics.tick();

    translate(moveX, moveY);  

    this.background(0,0,bgColor);

    drawObjects();

    setMaxAndMinScore();

  }
  catch(Exception e) {
    System.out.print(e);
  }
}

void setMaxAndMinScore() {

  int tempMax = 0;
  int tempMin = 2147483647;  
  Iterator<Particle> iter = friendsTable.keySet().iterator();

  while(iter.hasNext()) {
    Friend f = friendsTable.get(iter.next());

    int score = getScore(f);

    //exclude me score
    if(f.id != "me") {
      if(score > tempMax) {
        tempMax = score;
      }

      if(score < tempMin) {
        tempMin = score;
      }
    }
  }

  if(tempMax != this.maxScore) {
    this.maxScore = tempMax;    
    setMaxScore();
  }

  if(tempMin != this.minScore) {
    this.minScore = tempMin;
  }

  if(this.minScore < this.threshold) {
    this.minScore = this.threshold;
  }

  iter = friendsTable.keySet().iterator();
  
  while(iter.hasNext()) {
    Friend f = friendsTable.get(iter.next());
    setDistance(f.id, convertScoreToDistance(getScore(f)));
  }
}

void drawObjects() {

  //grabbed object process
  if(grabbed != null) {
    grabbed.position().set(mouseX + absPointX, mouseY + absPointY, 0);
  }

  //draw Springs
  for(int i = 0; i < physics.numberOfSprings(); i++) {
    Spring s = physics.getSpring(i);

    Particle p = s.getOneEnd();
    if(me.equals(p)) {
      p = s.getTheOtherEnd();
    }

    Friend f = ((Friend)friendsTable.get(p));
    int score = getScore(f);

    if(p.equals(me) || score >= this.threshold) {    
      if(s.isOff()) {
        s.turnOn();
      }
      drawSpring(s);
    }
    else {
      s.turnOff();
    }
  }

  //draw Particles
  int h = 229;
  int s = 0;
  int v = 80;

  //  int numberOfParticles = physics.numberOfParticles();
  //  objDiameter = getDiameter(numberOfParticles);

  textSize(10);
  this.textAlign(LEFT);
  text("Number of Friends: " + (physics.numberOfParticles() - 1), 10, 10, 0);
//  text("Score Max: " + maxScore + ", Min:" + minScore, 10, 25, 0);  
//  text("Threshold:" + threshold, 10, 40, 0);
//  text("friendsTable:" + (friendsTable.size() - 1), 10, 55, 0);
  //  text("objDiameter:" + objDiameter, 10, 85, 0);

  //Draw particles
  for(int i = 0; i < physics.numberOfParticles(); i++) {

    Particle p = physics.getParticle(i);

    Friend f = ((Friend)friendsTable.get(p));
    int score = getScore(f);

    if(p.equals(me) || score >= this.threshold) {    

      double d = getDistance(p, me);

      s = 95 - (int)d/2;
      v = 75;

      if(s < 0) { 
        s = 0;
        v = 100;
      }

      fill(h, s, v);
      float distance = getDistance(p, me);
      float diameter = getDiameter(distance);    
      if (p.equals(grabbed) || (abs(mouseX  + absPointX - p.position().x()) < diameter && abs(mouseY + absPointY - p.position().y()) < diameter)) {
        drawParticle(p, objDiameter + 10);
      }
      else {
        drawParticle(p);
      }
    }
  }

  //Show names
  this.textAlign(CENTER, CENTER);  

  //variable for text on top layer
  String topText = null;
  float topX = 0, topY = 0, topDiameter = 0;

  for(int i = 0; i < physics.numberOfParticles(); i++) {
    Particle p = physics.getParticle(i);

    Friend f = ((Friend)friendsTable.get(p));
    int score = getScore(f);

    if(p.equals(me) || score >= this.threshold) {    

      float distance = getDistance(p, me);
      float diameter = getDiameter(distance);
      float fontSize = getFontSize(distance);      
      String label = f.name;

      //when mouse over
      if (p.equals(grabbed) || (abs(mouseX  + absPointX - p.position().x()) < diameter && abs(mouseY + absPointY - p.position().y()) < diameter)) {

        if(!p.equals(me)) {
          label +=  " (" + getScore(f) + ")";
        }

        topText = label;
        topX = p.position().x();
        topY = p.position().y();
        topDiameter = diameter;
      } 
      else {

        //get first name
        int pos = label.indexOf(" ");
        if(pos > 0) {
          label = label.substring(0, pos);
        }
        fill(#111111);
        textSize(10);
        text(label, p.position().x() - absPointX, p.position().y() - absPointY + diameter, 0);
      }
    }
  }

  //Draw top object
  if(topX != 0 && topY != 0 && topDiameter != 0 && topText != null) {

    strokeWeight(1);   
    stroke(#000000);
    line(topX - absPointX, topY - absPointY, topX - absPointX + 5, topY - absPointY -  topDiameter*2);
    strokeWeight(0);

    textSize(20);       
    noStroke();
    fill(#FFFF99);
    rect(topX - absPointX - textWidth(topText)*1.2/2 + 5, topY - absPointY - (textAscent()+textDescent())*1.2/2 - topDiameter*2, textWidth(topText) * 1.2, (textAscent()+textDescent())*1.2);

    fill(#111111);
    text(topText, topX - absPointX + 5, topY - absPointY - topDiameter*2, 0);
  }
}



Particle addParticle() {
  return addParticle(maxDistance);
}

Particle addParticle(float distance) {
  return addParticle(width/2 + random(-20, 20), height/2 + random(-20, 20), distance);
}


Particle addParticle(float x, float y, float distance) {
  Particle p = physics.makeParticle(mass, x, y, 0);
  physics.makeSpring(p, me, springStrength, springDamp, distance);

  //avoid conflict
  for(int i = 0; i < physics.numberOfParticles(); i++) {
    Particle q = physics.getParticle(i);

    //check if it's a self
    if(!p.equals(q) && !q.equals(me)) {
      //physics.makeSpring(p, q, 0.1f, 0.001f, width/2);
      physics.makeAttraction(p, q, attracStrength, attracMinDist);
    }
  }
  return p;
}

float getDistance(Particle p, Particle q) {
  return sqrt(pow(p.position().x() - q.position().x(), 2) + pow(p.position().y() - q.position().y(),2));
}

float getDiameter(float distance) {

  float diameter = (maxDiameter * minDiameter * maxDistance)*1.5 / ((maxDiameter - minDiameter)*distance + (minDiameter * maxDistance));

  return diameter;
}

float getFontSize(float distance) {

  float maxFS = 20;
  float minFS = 3;
  float fSize = (maxFS * minFS * maxDistance) / ((maxFS - minFS)*distance + (minFS * maxDistance));

  return fSize;
}

/*
*  Public methods for javascript
 *
 */
public void addFriend(String id, String name, int numberOfMessages, int numberOfPosts, int numberOfComments, int numberOfLikes) {

  Friend f = new Friend(id, name);

  f.numberOfMessages = numberOfMessages;
  f.numberOfPosts = numberOfPosts;
  f.numberOfComments = numberOfComments;
  f.numberOfLikes = numberOfLikes;

  int score = getScore(f);

  Particle p = addParticle();
  if(p != null) {
    friendsTable.put(p, f);
    particleTable.put(id, p);

    if(score > maxScore) {
      maxScore = score;
    }

    if(score < minScore) {
      minScore = score;
    }

    //reset distance
    setDistance(id, convertScoreToDistance(score));
  }
}

public void addFriend(String id, String name) {
  Particle p = addParticle();
  if(p != null) {
    friendsTable.put(p, new Friend(id,name));
    particleTable.put(id, p);
  }
}

//set distance between me and friend
public void setDistance(String id, float distance) {
  setDistance("me", id, distance);
}

void setDistance(String id1, String id2, float distance) {

  Particle p = particleTable.get(id1);
  Particle q = particleTable.get(id2);

  if(p != null && q != null) {
    for(int i = 0; i < physics.numberOfSprings(); i++) {
      Spring s = physics.getSpring(i);
      if((q.equals(s.getOneEnd()) && p.equals(s.getTheOtherEnd())) || (p.equals(s.getOneEnd()) && q.equals(s.getTheOtherEnd()))) {
        s.setRestLength(distance);
      }
    }
  }
}

//add number of communication to a friend
public void addCount(String id, String type, int count) {

  //find friend instance
  Friend f = findFriend(id);

  //set count
  if(f != null) {

    if(type.equals("message")) {
      f.numberOfMessages += count;
    }
    if(type.equals("post")) {
      f.numberOfPosts += count;
    }
    if(type.equals("comment")) {
      f.numberOfComments += count;
    }
    if(type.equals("like")) {
      f.numberOfLikes += count;
    }    

    //reset distance
//    setDistance(id, convertScoreToDistance(getScore(f)));
  }
}

//dump json process
public void addJSONData(String json) {
  try {

    JSONObject data = new JSONObject(json);

    if(data.has("data") && !data.isNull("data")) {
      
      //friend data
      if(data.has("type") && !data.isNull("type") && data.getString("type").equals("friend")) {
        
        JSONArray friends = data.getJSONArray("data");
        for(int i = 0; i < friends.length(); i++) {
          JSONObject friend = (JSONObject)friends.get(i);

          String id = friend.getString("fId");
          String name = friend.getString("name");

          //Add Friend
          addFriend(id, name);
        }
      }
      //count data
      else {

        JSONObject friends = data.getJSONObject("data");
        Iterator iter = friends.keys();
        while(iter.hasNext()) {
          String id = (String)iter.next();
          JSONObject countData = friends.getJSONObject(id);
          Iterator iter2 = countData.keys();
          while(iter2.hasNext()) {
            String flag = (String)iter2.next();
            int count = countData.getInt(flag);

            //flag to upperDataType eg)message
            String upperDataType = getUpperDataTypeByFlagMode(flag);

            if(upperDataType != null) {
              addCount(id, upperDataType, count);
            }
          }
        }
      }
    }
  }
  catch(Exception e) {
    System.out.println(e.getMessage());
  }
}

String getUpperDataTypeByFlagMode(String flagMode) {

  String upperDataType = null;

  int message_bitmask = 3;
  int post_bitmask = 12;
  int comment_bitmask = 4080;
  int like_bitmask = 1044480;

  int mode = Integer.parseInt(flagMode);
  if(mode > 0) {

    if((message_bitmask & mode) == mode) {
      upperDataType = "message";
    }
    if((post_bitmask & mode) == mode) {
      upperDataType = "post";
    }
    if((comment_bitmask & mode) == mode) {
      upperDataType = "comment";
    }
    if((like_bitmask & mode) == mode) {
      upperDataType = "like";
    }
  }
  return upperDataType;
}

Friend findFriend(String id) {
  Friend f = null;
  try {
    f = friendsTable.get(particleTable.get(id));
  }
  catch(Exception e) {
    System.out.println(e);
  }
  return f;
}

public void setMaxDistance(int distance) {
  this.maxDistance = distance;
}

public int getNumberOfFriends(){
  return (physics.numberOfParticles() - 1);
}

float convertScoreToDistance(int score) {

  float distance = maxDistance;
  if(score != minScore) {
    float k2 = ((maxDistance * minScore) - (minDistance * maxScore))/(maxDistance - minDistance);
    float k1 = maxDistance * (minScore - k2);
    //		float k1 = minD*(maxS - k2);
    distance = k1/(score - k2);
  }
  return distance;
}

public int getMaxScore() {
  return this.maxScore;
}

public void clearGraph() {
  physics.clear();
  friendsTable.clear();
  particleTable.clear();
  initProgram();
}

/*
 * set weights
 */
public void setMessageWeight(int weight) {
  this.messageWeight = weight;
}
public void setPostWeight(int weight) {
  this.postWeight = weight;
}
public void setCommentWeight(int weight) {
  this.commentWeight = weight;
}
public void setLikeWeight(int weight) {
  this.likeWeight = weight;
}

/*
 * set checked
 */
public void setMessageChecked(boolean check) {
  this.messageChecked = check;
}
public void setPostChecked(boolean check) {
  this.postChecked = check;
}
public void setCommentChecked(boolean check) {
  this.commentChecked = check;
}
public void setLikeChecked(boolean check) {
  this.likeChecked = check;
}

/*
 * set threshold
 */
public void setThreshold(int value) {
  this.threshold = value;
}

/* 
 *  A Method to check this applet is loaded 
 *  and ready to access FROM JAVASCRIPT
 */
public void isUp(){
  //Do Nothing
}

//Event Handlers
void mousePressed() {
  for(int i = 0; i < physics.numberOfParticles(); i++) {
    Particle p = physics.getParticle(i);
    if(abs(mouseX - p.position().x() + absPointX) < objDiameter && abs(mouseY - p.position().y() + absPointY) < objDiameter) {
      this.grabbed = p;
    }
  }
  if(grabbed == null) {
    prevMouseX = mouseX;
    prevMouseY = mouseY;
  }

  /*
   * TEST CODE : reset distance between me and friends
   *
   */
  //  for(int i = 1; i<physics.numberOfParticles();i++){
  //    setScore("id"+i, int(random(0, 300)));
  //  }
}

void mouseReleased() {
  if(grabbed != null) {
    Particle tmp = grabbed;
    this.grabbed = null;
    if(!tmp.equals(me) && !isDragged) {
      Friend f = (Friend)friendsTable.get(tmp);
      linkToFriendshipPage(f.id);
    }
  }
  isDragged = false;
}

void mouseDragged() {
  if(grabbed == null) {
    moveX = mouseX - prevMouseX;
    moveY = mouseY - prevMouseY;
    prevMouseX = mouseX;
    prevMouseY = mouseY;
    absPointX = absPointX - moveX;
    absPointY = absPointY - moveY;
  } 
  else {
    isDragged = true;
  }
}

void linkToFriendshipPage(String id) {
  if(id != "0") {
    try {
      JSObject window = JSObject.getWindow(this);
      window.eval("linkToFriendshipPage("+id+")");
    }
    catch(JSException e) {
    }
  }
}

void setMaxScore() {
  try {
    JSObject window = JSObject.getWindow(this);  
    window.eval("setMaxScore("+ this.maxScore +")");
  }
  catch(JSException e) {
  }
}

//Drawing functions
void drawParticle(Particle p) {
  float diameter = 20;
  if(me != null) {
    float distance = getDistance(p, me);
    diameter = getDiameter(distance);
  }
  drawParticle(p.position().x(), p.position().y(), diameter);
}

void drawParticle(Particle p, float diameter) {
  drawParticle(p.position().x(), p.position().y(), diameter);
}

void drawParticle(float x, float y) {
  drawParticle(x,y,objDiameter);
}

void drawParticle(float x, float y, float diameter ) {
  ellipse(x - absPointX, y - absPointY, diameter, diameter);
}

void drawSpring(Spring s) {
  stroke(#333399);
  this.line(s.getOneEnd().position().x() - absPointX, s.getOneEnd().position().y() - absPointY, s.getTheOtherEnd().position().x() - absPointX, s.getTheOtherEnd().position().y() - absPointY);
}

int getScore(Friend f) {
  int score = 0;

  if(this.messageChecked) {
    score += (f.numberOfMessages * this.messageWeight);
  }
  if(this.postChecked) {
    score += (f.numberOfPosts * this.postWeight);
  }
  if(this.commentChecked) {
    score += (f.numberOfComments * this.commentWeight);
  }
  if(this.likeChecked) {
    score += (f.numberOfLikes * this.likeWeight);
  }

  return score;
}

//Inner Class
class Friend {
  String id;
  String name;
  Particle p;

  public int numberOfMessages = 0;
  public int numberOfPosts = 0;
  public int numberOfComments = 0;
  public int numberOfLikes = 0;

  Friend(String id, String name) {
    this.id = id;
    this.name = name;
  }
  void setParticle(Particle p) {
    this.p = p;
  }
}

